package br.usp.ime.ingpos.web.controllers;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;

import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.interceptor.download.FileDownload;
import br.com.caelum.vraptor.interceptor.multipart.UploadedFile;
import br.com.caelum.vraptor.validator.Validations;
import br.usp.ime.ingpos.modelo.Bolsa;
import br.usp.ime.ingpos.modelo.Candidato;
import br.usp.ime.ingpos.modelo.Curriculo;
import br.usp.ime.ingpos.modelo.DisciplinaEspecial;
import br.usp.ime.ingpos.modelo.FormacaoAcademica;
import br.usp.ime.ingpos.modelo.IniciacaoCientifica;
import br.usp.ime.ingpos.modelo.TipoDeFormacao;
import br.usp.ime.ingpos.modelo.TipoPerfil;
import br.usp.ime.ingpos.modelo.Usuario;
import br.usp.ime.ingpos.services.CartaDeRecomendacaoService;
import br.usp.ime.ingpos.services.CurriculoService;
import br.usp.ime.ingpos.services.UploadService;
import br.usp.ime.ingpos.services.UsuarioService;
import br.usp.ime.ingpos.web.interceptors.RestrictAccessPerfil;
import br.usp.ime.ingpos.web.interceptors.Transactional;

@Resource
public class CurriculoController
{

    private final Result result;
    private final Validator validador;
    private final CurriculoService curriculoService;
    private final UsuarioService usuarioService;
    private final UploadService uploadService;

    public CurriculoController(
        final Result result,
        final Validator validator,
        final CartaDeRecomendacaoService cartaDeRecomendacaoService,
        final CurriculoService curriculoService,
        final UsuarioService usuarioService,
        final UploadService uploadService )
    {
        this.result = result;
        this.validador = validator;
        this.curriculoService = curriculoService;
        this.usuarioService = usuarioService;
        this.uploadService = uploadService;
    }

    private void carregarDadosDaPagina()
    {
        result.include( "tiposDeFormacao", TipoDeFormacao.getTiposDeFormacao() );

        final Curriculo curriculo = curriculoService.getCurriculoUsuarioAtual();
        if( curriculo != null ) {

            final List<FormacaoAcademica> formacoesAcademicas = new ArrayList<FormacaoAcademica>();
            final List<IniciacaoCientifica> iniciacoesCientificas = new ArrayList<IniciacaoCientifica>();
            final List<Bolsa> bolsas = new ArrayList<Bolsa>();
            final List<DisciplinaEspecial> disciplinasEspeciais = new ArrayList<DisciplinaEspecial>();

            formacoesAcademicas.addAll( curriculo.getFormacoesAcademicas() );
            iniciacoesCientificas.addAll( curriculo.getIniciacoesCientificas() );
            bolsas.addAll( curriculo.getBolsas() );
            disciplinasEspeciais.addAll( curriculo.getDisciplinasEspeciais() );

            result.include( "curriculo", curriculo );
            result.include( "formacoesAcademicas", formacoesAcademicas );
            result.include( "iniciacoesCientificas", iniciacoesCientificas );
            result.include( "bolsas", bolsas );
            result.include( "disciplinasEspeciais", disciplinasEspeciais );

            result.include( "arquivoDiploma", getFileNamePfd( curriculo.getNomeArquivoDiploma() ) );
            result.include( "arquivoHistorico",
                getFileNamePfd( curriculo.getNomeArquivoHistorico() ) );
            result.include( "arquivoPoscomp", getFileNamePfd( curriculo.getNomeArquivoPoscomp() ) );
            result.include("arquivoDiplomaMestrado", getFileNamePfd( curriculo.getNomeArquivoDiplomaMestrado() ));
            result.include("arquivoHistoricoMestrado", getFileNamePfd( curriculo.getNomeArquivoHIstoricoMestrado() ));
        }
    }

    private String getFileNamePfd(
        String nomeArquivo )
    {
        if( nomeArquivo == null )
            return "";
        else {
            StringBuilder fileName = new StringBuilder();
            fileName.append( nomeArquivo );
            fileName.append( ".pdf" );
            return fileName.toString();
        }
    }

    @Get
    @Path( "/curriculo/dadosCurriculo" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void dadosCurriculo()
    {
        carregarDadosDaPagina();
    }

    @Post
    @Path( "/curriculo/dadosCurriculo" )
    @Transactional
    public void dadosCurriculo(
        final Curriculo curriculo,
        final UploadedFile diploma,
        final UploadedFile historico,
        final UploadedFile resultadoPoscomp,
        final UploadedFile historicoMestrado,
        final UploadedFile diplomaMestrado)
    {
        try {

            final Curriculo curriculoPersistido = curriculoService.getCurriculoUsuarioAtual();
            validador.onErrorRedirectTo( getClass() ).dadosCurriculo();
            validador.checking( new Validations() {
                {
                    that(
                        ( diploma == null )
                            || ( ( diploma != null ) && ( diploma.getContentType().equals( "application/pdf" ) ) ),
                        "erro_cadastro_curriculo_upload_diploma", "erro_upload_arquivo_pdf" );
                    that(
                        ( historico == null )
                            || ( ( historico != null ) && ( historico.getContentType().equals( "application/pdf" ) ) ),
                        "erro_cadastro_curriculo_upload_historico", "erro_upload_arquivo_pdf" );
                    that(
                        ( resultadoPoscomp == null )
                            || ( ( resultadoPoscomp != null ) && ( resultadoPoscomp.getContentType().equals( "application/pdf" ) ) ),
                        "erro_cadastro_curriculo_upload_resultado_poscomp",
                        "erro_upload_arquivo_pdf" );
                    that(
                        ( ! curriculo.getPosComp().isRealizouPosComp() && resultadoPoscomp == null )
                            || ( curriculo.getPosComp().isRealizouPosComp() && ( resultadoPoscomp != null || ( resultadoPoscomp == null && curriculoPersistido.getNomeArquivoPoscomp() != null ) ) ),
                        "erro_cadastro_curriculo_upload_resultado_poscomp",
                        "erro_upload_pos_comp_obrigatorio" );
                }
            } );

            validador.onErrorForwardTo( getClass() ).dadosCurriculo(); 

            if( diploma != null ) {
                curriculo.setArquivoDiplomaPDF( uploadService.convertePDFParaByteArray( diploma ) );
                curriculo.setNomeArquivoDiploma( uploadService.getNomeDoArquivoSemExtensao( diploma ) );
            } else {
                if( curriculoPersistido.getArquivoDiplomaPDF() != null ) {
                    curriculo.setArquivoDiplomaPDF( curriculoPersistido.getArquivoDiplomaPDF() );
                    curriculo.setNomeArquivoDiploma( curriculoPersistido.getNomeArquivoDiploma() );
                }
            }

            if( historico != null ) {
                curriculo.setArquivoHistoricoPDF( uploadService.convertePDFParaByteArray( historico ) );
                curriculo.setNomeArquivoHistorico( uploadService.getNomeDoArquivoSemExtensao( historico ) );
            } else {
                if( curriculoPersistido.getArquivoHistoricoPDF() != null ) {
                    curriculo.setArquivoHistoricoPDF( curriculoPersistido.getArquivoHistoricoPDF() );
                    curriculo.setNomeArquivoHistorico( curriculoPersistido.getNomeArquivoHistorico() );
                }
            }
            if( resultadoPoscomp != null ) {
                curriculo.setArquivoPoscompPDF( uploadService.convertePDFParaByteArray( resultadoPoscomp ) );
                curriculo.setNomeArquivoPoscomp( uploadService.getNomeDoArquivoSemExtensao( resultadoPoscomp ) );
            } else {
                if( curriculoPersistido.getArquivoPoscompPDF() != null ) {
                    curriculo.setArquivoPoscompPDF( curriculoPersistido.getArquivoPoscompPDF() );
                    curriculo.setNomeArquivoPoscomp( curriculoPersistido.getNomeArquivoPoscomp() );
                }
            }
            
            if( diplomaMestrado != null ) {
                curriculo.setArquivoDiplomaMestradoPDF( ( uploadService.convertePDFParaByteArray( diplomaMestrado ) ));
                curriculo.setNomeArquivoDiplomaMestrado( ( uploadService.getNomeDoArquivoSemExtensao( diplomaMestrado ) ));
            } else {
                if( curriculoPersistido.getArquivoDiplomaMestradoPDF() != null ) {
                    curriculo.setArquivoDiplomaMestradoPDF( ( curriculoPersistido.getArquivoDiplomaMestradoPDF()));
                    curriculo.setNomeArquivoDiplomaMestrado( ( curriculoPersistido.getNomeArquivoDiplomaMestrado()) );
                }
            }
            
            if( historicoMestrado != null ) {
                curriculo.setArquivoHistoricoMestradoPDF(( uploadService.convertePDFParaByteArray( historicoMestrado ) ));
                curriculo.setNomeArquivoHIstoricoMestrado( ( uploadService.getNomeDoArquivoSemExtensao( historicoMestrado )) );
            } else {
                if( curriculoPersistido.getArquivoHistoricoMestradoPDF() != null ) {
                    curriculo.setArquivoHistoricoMestradoPDF(( curriculoPersistido.getArquivoHistoricoMestradoPDF()) );
                    curriculo.setNomeArquivoHIstoricoMestrado( ( curriculoPersistido.getNomeArquivoHIstoricoMestrado() ) );
                }
            }

            curriculoService.atualizarCurriculo( curriculo );
            result.include( "messages", "cadastro_curriculo_sucesso" );
            result.forwardTo( this ).dadosCurriculo();
        } catch( IOException e ) {

            validador.checking( new Validations() {
                {
                    that( false, "erro_converter_pdf", "erro_upload_erro_converter_pdf" );

                }
            } );
            validador.onErrorRedirectTo( getClass() ).dadosCurriculo();

            // TODO Incluir mensagem de erro pdf
            e.printStackTrace();
        }

    }

    @Get
    @Path( "/curriculo/diploma/{hash}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoDiplomaView(
        final String hash )
    {
        return curriculoService.getArquivoDiplomaPDF( usuarioService.procurarPorHash( hash ) );
    }

    @Get
    @Path( "/curriculo/historico/{hash}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoHistoricoView(
        final String hash )
    {
        return curriculoService.getArquivoHistoricoPDF( usuarioService.procurarPorHash( hash ) );
    }

    @Get
    @Path( "/curriculo/poscomp/{hash}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoPosCompView(
        final String hash )
    {
        return curriculoService.getArquivoPosCompPDF( usuarioService.procurarPorHash( hash ) );
    }
    
    @Get
    @Path( "/curriculo/diplomaMestrado/{hash}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoDiplomaMestradoView(
        final String hash )
    {
        return curriculoService.getArquivoDiplomaMestradoPDF( usuarioService.procurarPorHash( hash ) );
    }
    
    @Get
    @Path( "/curriculo/historicoMestrado/{hash}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.CANDIDATO, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoHistoricoMestradoView(
        final String hash )
    {
        return curriculoService.getArquivoHistoricoMestradoPDF( usuarioService.procurarPorHash( hash ) );
    }

    @Get
    @Path( "/curriculo/dadosCurriculo/diploma" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoDiploma()
    {
        return curriculoService.getArquivoDiplomaPDF( curriculoService.getUsuarioAtual() );
    }
    
    @Get
    @Path( "/curriculo/dadosCurriculo/diplomaMestrado" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoDiplomaMestrado()
    {
        return curriculoService.getArquivoDiplomaMestradoPDF( curriculoService.getUsuarioAtual() );
    }
    
    @Get
    @Path( "/curriculo/dadosCurriculo/historicoMestrado" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoHistoricoMestrado()
    {
        return curriculoService.getArquivoHistoricoMestradoPDF( curriculoService.getUsuarioAtual() );
    }

    @Get
    @Path( "/curriculo/dadosCurriculo/historico" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoHistorico()
    {
        Curriculo curriculo = curriculoService.getCurriculoUsuarioAtual();
        if( curriculo.getNomeArquivoHistorico() != null ) {
            String contentType = "application/pdf";
            StringBuilder fileName = new StringBuilder();
            fileName.append( curriculo.getNomeArquivoHistorico() );
            fileName.append( ".pdf" );
            File file = new File( fileName.toString() );
            try {
                FileUtils.writeByteArrayToFile( file, curriculo.getArquivoHistoricoPDF() );

            } catch( IOException e ) {
                // TODO Implementar a tela de erro
                e.printStackTrace();
            }
            return new FileDownload( file, contentType, fileName.toString() );
        } else {
            return null;
        }
    }

    @Get
    @Path( "/curriculo/dadosCurriculo/poscomp" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public FileDownload downloadArquivoPoscomp()
    {
        Curriculo curriculo = curriculoService.getCurriculoUsuarioAtual();
        if( curriculo.getNomeArquivoPoscomp() != null ) {
            String contentType = "application/pdf";
            StringBuilder fileName = new StringBuilder();
            fileName.append( curriculo.getNomeArquivoPoscomp() );
            fileName.append( ".pdf" );
            File file = new File( fileName.toString() );
            try {
                FileUtils.writeByteArrayToFile( file, curriculo.getArquivoPoscompPDF() );

            } catch( IOException e ) {
                // TODO Implementar a tela de erro
                e.printStackTrace();
            }
            return new FileDownload( file, contentType, fileName.toString() );
        } else {
            return null;
        }
    }

    @Get
    @Path( "/curriculo/editarFormacaoAcademica/{formacaoAcademica.formacaoAcademicaId}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void editarFormacaoAcademica(
        FormacaoAcademica formacaoAcademica )
    {
        result.include(
            "formacaoAcademica",
            curriculoService.getFormacaoAcademicaParaEdicao( formacaoAcademica.getFormacaoAcademicaId() ) );

        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/removerFormacaoAcademica/{formacaoAcademica.formacaoAcademicaId}" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void removerFormacaoAcademica(
        FormacaoAcademica formacaoAcademica )
    {
        curriculoService.removerFormacaoAcademica( formacaoAcademica.getFormacaoAcademicaId() );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Post
    @Path( "/curriculo/adicionaFormacaoAcademica" )
    @Transactional
    public void adicionaFormacaoAcademica(
        final FormacaoAcademica formacaoAcademica )
    {
        validador.checking( new Validations() {
            {
                that( formacaoAcademica.getTipoDeFormacao() != null,
                    "cadastro_curriculo_tipo_formacao",
                    "cadastro_curriculo_tipo_formacao_erro_vazio" );

                // TODO: incluir outras validacoes
            }
        } );

        validador.onErrorForwardTo( getClass() ).dadosCurriculo();

        curriculoService.adicionaFormacaoAcademica( formacaoAcademica );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/editarIniciacaoCientifica/{iniciacaoCientifica.iniciacaoCientificaId}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void editarIniciacaoCientifica(
        IniciacaoCientifica iniciacaoCientifica )
    {
        result.include(
            "iniciacaoCientifica",
            curriculoService.getIniciacaoCientificaParaEdicao( iniciacaoCientifica.getIniciacaoCientificaId() ) );

        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/removerIniciacaoCientifica/{iniciacaoCientifica.iniciacaoCientificaId}" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void removerIniciacaoCientifia(
        IniciacaoCientifica iniciacaoCientifica )
    {
        curriculoService.removerIniciacaoCientifica( iniciacaoCientifica.getIniciacaoCientificaId() );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Post
    @Path( "/curriculo/adicionaIniciacaoCientifica" )
    @Transactional
    public void adicionaIniciacaoCientifica(
        final IniciacaoCientifica iniciacaoCientifica )
    {
        // validador.checking( new Validations() {
        // {
        // that( formacaoAcademica.getTipoDeFormacao() != null,
        // "cadastro_curriculo_tipo_formacao",
        // "cadastro_curriculo_tipo_formacao_erro_vazio" );
        //
        // // TODO: incluir outras validacoes
        // }
        // } );

        validador.onErrorForwardTo( getClass() ).dadosCurriculo();
        curriculoService.adicionaIniciacaoCientifica( iniciacaoCientifica );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/editarBolsa/{bolsa.bolsaId}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void editarBolsa(
        Bolsa bolsa )
    {
        result.include( "bolsa", curriculoService.getBolsaParaEdicao( bolsa.getBolsaId() ) );

        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/removerBolsa/{bolsa.bolsaId}" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void removerBolsa(
        Bolsa bolsa )
    {
        curriculoService.removerBolsa( bolsa.getBolsaId() );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Post
    @Path( "/curriculo/adicionaBolsa" )
    @Transactional
    public void adicionaBolsa(
        final Bolsa bolsa )
    {
        // validador.checking( new Validations() {
        // {
        // that( bolsa.getTipoDeFormacao() != null,
        // "cadastro_curriculo_tipo_formacao",
        // "cadastro_curriculo_tipo_formacao_erro_vazio" );
        //
        // // TODO: incluir outras validacoes
        // }
        // } );

        validador.onErrorForwardTo( getClass() ).dadosCurriculo();

        curriculoService.adicionaBolsa( bolsa );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/editarDisciplinaEspecial/{disciplinaEspecial.disciplinaEspecialID}" )
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void editarDisciplinaEspecial(
        DisciplinaEspecial disciplinaEspecial )
    {
        result.include( "disciplinaEspecial",
            curriculoService.getDisciplinaParaEdicao( disciplinaEspecial.getDisciplinaEspecialID() ) );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Get
    @Path( "/curriculo/removerDisciplinaEspecial/{disciplinaEspecial.disciplinaEspecialID}" )
    @Transactional
    @RestrictAccessPerfil( values = {
        TipoPerfil.COORDENADOR, TipoPerfil.PROFESSOR, TipoPerfil.SECRETARIA
    } )
    public void removerDisciplinaEspecial(
        DisciplinaEspecial disciplinaEspecial )
    {
        curriculoService.removerDisciplinaEspecial( disciplinaEspecial.getDisciplinaEspecialID() );
        result.redirectTo( getClass() ).dadosCurriculo();
    }

    @Post
    @Path( "/curriculo/adicionarDisciplinaEspecial" )
    @Transactional
    public void adicionarDisciplinaEspecial(
        final DisciplinaEspecial disciplinaEspecial )
    {
        validador.onErrorForwardTo( getClass() ).dadosCurriculo();
        curriculoService.adicionarDisciplina( disciplinaEspecial );
        result.redirectTo( getClass() ).dadosCurriculo();
    }
}